﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace ZhaoXi.Http.Client
{
    /// <summary>
    /// HttpClientHelper的封装
    /// post(新增)、get(查询)、put(修改)、delete(删除)等请求的封装
    /// </summary>
    public class HttpClientHelper
    {
        #region 单例模式
        /// <summary>
        /// HttpClient封装操作类
        /// </summary>
        private static HttpClientHelper? httpClientHelper = null;
        /// <summary>
        /// httpClient实例
        /// </summary>
        private HttpClient httpClient;

        /// <summary>
        ///  构造方法私有，用于单例
        /// </summary>
        private HttpClientHelper() { }

        /// <summary>
        /// 获取当前类的实例
        /// </summary>
        /// <returns></returns>
        public static HttpClientHelper GetInstance()
        {
            if (httpClientHelper != null)
            {
                return httpClientHelper;
            }
            else
            {
                HttpClientHelper httpClientHelper = new HttpClientHelper();
                //取消使用默认的Cookies
                HttpClientHandler handler = new HttpClientHandler()
                {
                    UseCookies = false,
                    AutomaticDecompression = DecompressionMethods.GZip // 设置自动解压缩
                };
                httpClientHelper.httpClient = new HttpClient(handler);
                return httpClientHelper;
            }
        }
        #endregion

        #region Get请求的函数封装
        //需要考虑的场景：
        //1. 通过字符串传值---URL传值
        //2. 通过头信息传值

        /// <summary>
        /// Get请求,如果有参数，就通过字符串传值
        /// </summary>
        /// <param name="url">Get请求的URL,URL中可能拼装的有Query参数</param>
        /// <returns></returns>
        public HttpResponseMessage Get(string url)
        {
            return this.Get(url, new Dictionary<string, string>());
        }

        /// <summary>
        /// Get方法请求，参数可以通过查询字符串传递，也可以通过请求头信息headers传递
        /// </summary>
        /// <param name="url">请求的URL地址</param>
        /// <param name="headers">请求的头信息（注意，只能是字符串）</param>
        /// <returns></returns>
        public HttpResponseMessage Get(string url, Dictionary<string, string> headers)
        {
            //通过SendAsync函数执行
            {
                HttpRequestMessage request = new HttpRequestMessage()
                {
                    RequestUri = new Uri(url), // 路径
                    Method = HttpMethod.Get, // 请求方法
                };
                if (headers != null && headers.Count > 0)
                {
                    request.Headers.Clear();
                    foreach (var header in headers) // 遍历添加所有的头信息
                    {
                        request.Headers.Add(header.Key, header.Value);
                    }
                }
                // 通用的请求方法
                HttpResponseMessage response = httpClient.SendAsync(request).Result.EnsureSuccessStatusCode();
                return response;
            }

            #region 方式二
            //httpClient.DefaultRequestHeaders.Clear();
            //foreach (var header in headers)
            //{
            //    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
            //}
            //HttpResponseMessage response = GetAsync(url).Result.EnsureSuccessStatusCode();
            // return response;
            #endregion
        }


        /// <summary>
        /// 异步版本的Get请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="headers">通过请求头信息headers传递参数</param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> GetAsync(string url, Dictionary<string, string> headers)
        {
            //通过SendAsync函数执行
            {
                HttpRequestMessage request = new HttpRequestMessage()
                {
                    RequestUri = new Uri(url),
                    Method = HttpMethod.Get,
                };
                if (headers != null && headers.Count > 0)
                {
                    request.Headers.Clear();
                    foreach (var header in headers)
                    {
                        request.Headers.Add(header.Key, header.Value);
                    }
                }
                return await httpClient.SendAsync(request);
            }

            #region 方式二
            //httpClient.DefaultRequestHeaders.Clear();
            //foreach (var header in headers)
            //{
            //    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
            //}
            //HttpResponseMessage response = GetAsync(url).Result.EnsureSuccessStatusCode();
            // return response;
            #endregion
        }

        /// <summary>
        /// GetAsync 异步函数请求,如果有参数，就通过字符串传值
        /// </summary>
        /// <param name="url">Get请求的URL,URL中可能拼装的有Query参数</param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> GetAsync(string url)
        {
            return await httpClient.GetAsync(url);
        }

        #endregion

        #region Post请求的函数封装 
        //需要考虑的场景：
        //1. 支持Url地址栏传值
        //2. 支持简单类型的标头传值（Header传值）
        //3. 支持Json格式的传值（body）
        //4. 支持form表单提交传值


        /// <summary>
        /// Post方法请求同步步函数(Form表单提交的场景) application/x-www-form-urlencoded格式
        /// </summary>
        /// <param name="url">请求URL地址</param>
        /// <param name="form">提交的表单内容</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public HttpResponseMessage Post(string url, List<KeyValuePair<string, string>>? form = null, Dictionary<string, string>? headers = null)
        {
            FormUrlEncodedContent? formUrlEncodedContent = null;
            if (form != null)
            {
                formUrlEncodedContent = new FormUrlEncodedContent(form);
            }
            if (headers != null && headers.Count > 0)
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            HttpResponseMessage response = httpClient.PostAsync(new Uri(url), formUrlEncodedContent).Result;
            httpClient.DefaultRequestHeaders.Clear();
            return response;
        }

        /// <summary>
        /// Post方法请求异步函数(Form表单提交的场景) application/x-www-form-urlencoded格式
        /// </summary>
        /// <param name="url">请求URL地址</param>
        /// <param name="form">提交的表单内容</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> PostAsync(string url, List<KeyValuePair<string, string>>? form = null, Dictionary<string, string>? headers = null)
        {
            FormUrlEncodedContent? formUrlEncodedContent = null;
            if (form != null)
            {
                formUrlEncodedContent = new FormUrlEncodedContent(form);
            }
            if (headers != null && headers.Count > 0)
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            var reponse = await httpClient.PostAsync(new Uri(url), formUrlEncodedContent);
            httpClient.DefaultRequestHeaders.Clear();
            return reponse;
        }

        /// <summary>
        /// Post方法请求 同步函数 （通过Body传递数据的方式）
        /// </summary>
        /// <param name="url">请求的URL地址</param>
        /// <param name="content">通过Body传递的具体数据-需要JSON格式的字符串</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public HttpResponseMessage Post(string url, string? content, Dictionary<string, string>? headers = null)
        {
            StringContent? stringContent = null;
            if (content != null)
            {
                stringContent = new StringContent(content, Encoding.UTF8);
            }

            if (headers != null && headers.Count > 0)
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            HttpResponseMessage response = httpClient.PostAsync(new Uri(url), stringContent).Result;
            httpClient.DefaultRequestHeaders.Clear();
            return response;
        }

        /// <summary>
        ///  Post方法请求 异步函数 （通过Body传递数据的方式）
        ///  这个是常用的方式，适用于需要传递JSON数据的场景
        /// </summary>
        /// <param name="url">请求地址URL</param>
        /// <param name="content">通过Body传递的具体数据-需要JSON格式的字符串</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> PostAsync(string url, string? content, Dictionary<string, string>? headers = null)
        {
            #region 添加json字符串到Body中
            StringContent? stringContent = null;
            if (content != null) // 如果有内容json字符串
            {
                stringContent = new StringContent(content, Encoding.UTF8, "application/json");
            }
            #endregion

            #region 添加头信息到请求中
            if (headers != null && headers.Count > 0) // 如果有头信息
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers) // 遍历添加所有的头信息
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            #endregion

            return await httpClient.PostAsync(new Uri(url), stringContent);
        }
        #endregion

        #region Put请求的函数封装 

        /// <summary>
        /// Put方法请求同步步函数(Form表单提交的场景) application/x-www-form-urlencoded格式
        /// </summary>
        /// <param name="url">请求URL地址</param>
        /// <param name="form">提交的表单内容</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public HttpResponseMessage Put(string url, List<KeyValuePair<string, string>>? form = null, Dictionary<string, string>? headers = null)
        {
            FormUrlEncodedContent? formUrlEncodedContent = null;
            if (form != null)
            {
                formUrlEncodedContent = new FormUrlEncodedContent(form);
            }
            if (headers != null && headers.Count > 0)
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            HttpResponseMessage response = httpClient.PutAsync(new Uri(url), formUrlEncodedContent).Result;
            httpClient.DefaultRequestHeaders.Clear();
            return response;
        }

        /// <summary>
        ///PutAsync方法请求异步函数(Form表单提交的场景) application/x-www-form-urlencoded格式
        /// </summary>
        /// <param name="url">请求URL地址</param>
        /// <param name="form">提交的表单内容</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> PutAsync(string url, List<KeyValuePair<string, string>>? form = null, Dictionary<string, string>? headers = null)
        {
            FormUrlEncodedContent? formUrlEncodedContent = null;
            if (form != null)
            {
                formUrlEncodedContent = new FormUrlEncodedContent(form);
            }
            if (headers != null && headers.Count > 0)
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            var reponse = await httpClient.PutAsync(new Uri(url), formUrlEncodedContent);
            httpClient.DefaultRequestHeaders.Clear();
            return reponse;
        }

        /// <summary>
        ///Put方法请求 同步函数 （通过Body传递数据的方式）
        /// </summary>
        /// <param name="url">请求的URL地址</param>
        /// <param name="content">通过Body传递的具体数据-需要JSON格式的字符串</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public HttpResponseMessage Put(string url, string? content, Dictionary<string, string>? headers = null)
        {
            StringContent? stringContent = null;
            if (content != null)
            {
                stringContent = new StringContent(content, Encoding.UTF8);
            }

            if (headers != null && headers.Count > 0)
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            HttpResponseMessage response = httpClient.PutAsync(new Uri(url), stringContent).Result;
            httpClient.DefaultRequestHeaders.Clear();
            return response;
        }

        /// <summary>
        ///  Put方法请求 异步函数 （通过Body传递数据的方式）
        ///  常用的方式，适用于需要传递JSON数据的场景
        /// </summary>
        /// <param name="url">请求地址URL</param>
        /// <param name="content">通过Body传递的具体数据-需要JSON格式的字符串</param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> PutAsync(string url, string? content, Dictionary<string, string>? headers = null)
        {
            StringContent? stringContent = null;
            if (content != null)
            {
                stringContent = new StringContent(content, Encoding.UTF8, "application/json");
            }
            if (headers != null && headers.Count > 0)
            {
                httpClient.DefaultRequestHeaders.Clear();
                foreach (var header in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
            }
            return await httpClient.PutAsync(new Uri(url), stringContent);

        }
        #endregion


        #region Delete请求的函数封装 - 与get请求类型-如果需要可以自己封装
        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <param name="paramList"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public HttpResponseMessage Delete(string url)
        {
            HttpResponseMessage response = httpClient.DeleteAsync(url).Result;
            return response;
        }




        /// <summary>
        /// 释放httpclient
        /// </summary>
        public void Release()
        {
            httpClient.Dispose();
        }



        /// <summary>
        /// 设置默认请求头
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void SetDefaultHeaders(string name, string value)
        {
            httpClient.DefaultRequestHeaders.Add(name, value);
        }

        /// <summary>
        /// 删除默认请求头
        /// </summary>
        /// <param name="name"></param>
        public void RemoveDefaultHeaders(string name)
        {
            httpClient.DefaultRequestHeaders.Remove(name);
        }
        #endregion
    }
}